package com.ling.pl.core.hibernate.orm;

import javassist.util.proxy.ProxyFactory;
import org.hibernate.EmptyInterceptor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author bo.wang
 * @since 2016-08-08
 */
@Component(UnByteCodeProxyInterceptor.BEAN_ID)
public class UnByteCodeProxyInterceptor extends EmptyInterceptor {
    public static final String BEAN_ID = "ling2.unByteCodeProxyInterceptor";
    private static final long serialVersionUID = -6422637558312349795L;
    private static boolean extraEnhancersInited;
    private static Method springCglibIsEnhancerMethod;

    public static Class<?> getProxyTargetType(Object bean) {
        Class<?> cl = bean.getClass();
        while (isProxy(cl)) {
            cl = cl.getSuperclass();
        }
        return cl;
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public static boolean isProxy(Class<?> cl) {
        boolean b = net.sf.cglib.proxy.Enhancer.isEnhanced(cl)
                || ProxyFactory.isProxyClass(cl);
        if (!b) {
            if (!extraEnhancersInited) {
                extraEnhancersInited = true;
                try {
                    Class enhancerType = forName("org.springframework.cglib.proxy.Enhancer");
                    springCglibIsEnhancerMethod = enhancerType.getMethod(
                            "isEnhanced", new Class[]{Class.class});
                } catch (Exception e) {
                    // do nothing
                }
            }

            if (springCglibIsEnhancerMethod != null) {
                try {
                    b = (Boolean) springCglibIsEnhancerMethod.invoke(null,
                            new Object[]{cl});
                } catch (Exception e) {
                    // do nothing
                }
            }
        }
        return b;
    }

    @SuppressWarnings("rawtypes")
    public static Class forName(String className) throws ClassNotFoundException {
        try {
            return org.apache.commons.lang.ClassUtils.getClass(className);
        } catch (Error e) {
            throw new ClassNotFoundException(e.getMessage(), e);
        }
    }

    @Override
    public String getEntityName(Object object) {
        if (object != null) {
            Class<?> cl = getProxyTargetType(object);
            return cl.getName();
        } else {
            return null;
        }
    }
}
